﻿using System;
using System.Threading.Tasks;
using System.Windows;
using OpenFileTransfer.Util.Extensions;
using OpenFileTransfer.Wpf.Database;
using OpenFileTransfer.Wpf.Models;
using OpenFileTransfer.Wpf.Repositories;
using OpenFileTransfer.Wpf.Services;
using OpenFileTransfer.Wpf.Views;
using Prism.Ioc;
using Prism.Unity;

namespace OpenFileTransfer.Wpf
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    // ReSharper disable once RedundantExtendsListEntry
    public partial class App : PrismApplication
    {
        protected override void OnExit(ExitEventArgs e)
        {
            base.OnExit(e);

            try
            {
                //反初始化服务
                UnInitService();
            }
            catch (Exception exception)
            {
                var logService = Container.Resolve<ILogService>();
                logService.Fatal($"UnInitService error: {exception.GetFullMessage()}.");
            }
        }

        protected override Window CreateShell()
        {
            InitService(); //初始化服务
            HandleException(); //处理异常
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            //注册单例服务
            containerRegistry.RegisterSingleton<ILogService, LogService>();
            containerRegistry.RegisterSingleton<IConfigService, ConfigService>();
            containerRegistry.RegisterSingleton<IUdpService, UdpService>();
            containerRegistry.RegisterSingleton<ICommunicationService, CommunicationService>();
            containerRegistry.RegisterSingleton<IWebSocketServerService, WebSocketServerService>();

            //注册瞬时服务
            //containerRegistry.Register<IHttpService, HttpService>();
            containerRegistry.RegisterSingleton<ISqliteService, SqliteService>();
            containerRegistry.Register<IRepository<DeviceInfoModel>, DeviceInfoRepository>();
        }

        #region Init/UnInit Service

        private void InitService()
        {
            //启动日志服务
            var logService = Container?.Resolve<ILogService>();
            logService?.Startup(@"Config/NLog.config");

            //准备SQLite数据库
            // ReSharper disable once IdentifierTypo
            var sqliteService = Container?.Resolve<ISqliteService>();
            sqliteService?.PrepareSqlite();

            //EF Core预热
            WarmupDatabase();

            //加载配置
            var configService = Container.Resolve<IConfigService>();
            configService?.LoadConfig(@"Config/AppSettings.xml");

            //启动UDP服务
            var udpService = Container.Resolve<IUdpService>();
            udpService?.Startup();

            //启动通信服务
            var communicationService = Container.Resolve<ICommunicationService>();
            communicationService?.Startup();

            //启动WebSocketServer
            var webSocketServerService = Container.Resolve<IWebSocketServerService>();
            webSocketServerService?.Startup();
        }

        private void WarmupDatabase()
        {
            Task.Run(() =>
            {
                using var dbContext = Container?.Resolve<SqliteDbContext>();

                // this is for demo purposes only, to make it easier
                // to get up and running
                dbContext?.Database.EnsureCreated();

                // load the entities into EF Core
                dbContext?.LoadEntities();

                // ReSharper disable once AssignmentIsFullyDiscarded
                //_ = dbContext.Model; //force the model creation
            });
        }

        private void UnInitService()
        {
            //关闭WebSocketServer
            var webSocketServerService = Container.Resolve<IWebSocketServerService>();
            webSocketServerService?.Shutdown();

            //关闭通信服务
            var communicationService = Container.Resolve<ICommunicationService>();
            communicationService?.Shutdown();

            //关闭UDP服务
            var udpService = Container.Resolve<IUdpService>();
            udpService?.Shutdown();

            //关闭日志服务
            var logService = Container?.Resolve<ILogService>();
            logService?.Shutdown();
        }

        #endregion

        //处理异常
        private void HandleException()
        {
            //处理除Task以外的所有线程异常
            AppDomain.CurrentDomain.UnhandledException += (_, args) =>
            {
                var logService = Container.Resolve<ILogService>();
                logService.Error($"AppDomain.CurrentDomain.UnhandledException: {args.ExceptionObject}");
            };

            //处理UI线程异常
            Current.DispatcherUnhandledException += (_, args) =>
            {
                var logService = Container.Resolve<ILogService>();
                logService.Error(
                    $"Application.Current.DispatcherUnhandledException: {args.Exception?.GetFullMessage()}");
                args.Handled = true; //标记已处理
            };

            //处理Task异常(依赖垃圾回收)
            TaskScheduler.UnobservedTaskException += (_, args) =>
            {
                var logService = Container.Resolve<ILogService>();
                logService.Error($"TaskScheduler.UnobservedTaskException: {args.Exception.GetFullMessage()}");
                args.SetObserved(); //设置异常已被观察
            };

            //Occurs when a thread exception is thrown and uncaught during execution of a delegate
            // by way of Dispatcher.Invoke or Dispatcher.BeginInvoke.
            Dispatcher.UnhandledException += (_, args) =>
            {
                var logService = Container.Resolve<ILogService>();
                logService.Error($"Dispatcher.UnhandledException: {args.Exception?.GetFullMessage()}");
                args.Handled = true; //标记已处理
            };

            //Occurs when a thread exception is thrown and uncaught during execution of a delegate
            // by way of Dispatcher.Invoke or Dispatcher.BeginInvoke.
            Dispatcher.UnhandledExceptionFilter += (_, args) =>
            {
                var logService = Container.Resolve<ILogService>();
                logService.Error($"Dispatcher.UnhandledExceptionFilter: {args.Exception?.GetFullMessage()}");
                args.RequestCatch = true; //抛出异常
            };
        }
    }
}
